{ "cells": [ { "cell_type": "markdown", "id": "d26e3b44", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "# Decomposing Qiskit circuits" ] }, { "cell_type": "markdown", "id": "f5994d25", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "In this notebook, we show how Qiskit circuits can be converted into Perceval circuits. To do so, we take the example of a simple gate-based circuit (a circuit producing GHZ states) and we show the translation to a linear optical circuit. We also show the equivalence between the two circuits." ] }, { "cell_type": "markdown", "id": "3ed1c79e", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "As usual we start by imported the useful libraries. Note that this notebook requires the installation of Qiskit (which can be easiliy done with `pip install qiskit`)." ] }, { "cell_type": "code", "execution_count": 1, "id": "9dea723b", "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "import perceval as pcvl\n", "from perceval.components import catalog\n", "from perceval.converters import QiskitConverter\n", "\n", "from qiskit import QuantumCircuit\n", "from qiskit.quantum_info import Statevector" ] }, { "cell_type": "markdown", "id": "61e8fe05", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "## GHZ State generation in Qiskit" ] }, { "cell_type": "markdown", "id": "57423a74", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "We first define the circuit generating GHZ states of 3 qubits with Qiskit. To do so, we first act with a Hadamard gate on qubit 0 to put in superposition of state $|0\\rangle$ and $|1\\rangle$. Then we perform two CNOT gates using qubit 0 as control and qubits 1 and 2 as targets." ] }, { "cell_type": "code", "execution_count": 2, "id": "aef291d3", "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": " ┌───┐ \nq_0: ┤ H ├──■────■──\n └───┘┌─┴─┐ │ \nq_1: ─────┤ X ├──┼──\n └───┘┌─┴─┐\nq_2: ──────────┤ X ├\n └───┘", "text/html": "
     ┌───┐          \nq_0: ┤ H ├──■────■──\n     └───┘┌─┴─┐  │  \nq_1: ─────┤ X ├──┼──\n          └───┘┌─┴─┐\nq_2: ──────────┤ X ├\n               └───┘
" }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create a Quantum Circuit acting on the q register\n", "circuit = QuantumCircuit(3)\n", "\n", "# Add a H gate on qubit 0\n", "circuit.h(0)\n", "\n", "# Add CX (CNOT) gates on control qubit 0 and target qubits 1 and 2\n", "circuit.cx(0, 1)\n", "circuit.cx(0, 2)\n", "\n", "# Draw the circuit\n", "circuit.draw()" ] }, { "cell_type": "markdown", "id": "cca607ca", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "We display the final state when starting from the input state $|000\\rangle$." ] }, { "cell_type": "code", "execution_count": 3, "id": "7edaa2b3", "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": "", "text/latex": "$$\\frac{\\sqrt{2}}{2} |000\\rangle+\\frac{\\sqrt{2}}{2} |111\\rangle$$" }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Set the initial state of the simulator to the ground state using from_int\n", "state = Statevector.from_int(0, 2**3)\n", "\n", "# Evolve the state by the quantum circuit\n", "state = state.evolve(circuit)\n", "\n", "#draw using latex\n", "state.draw('latex')" ] }, { "cell_type": "markdown", "id": "9a4a941f", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "## Conversion to Perceval" ] }, { "cell_type": "markdown", "id": "9d6365aa", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "With the use of `QiskitConverter`, we can transform the Qiskit circuit into a Perceval circuit. It uses 2 modes per qubit and additional modes for ancillary photons to perform deterministically two-qubit gates. Below the first six modes correspond to the three logical qubits (see the 'Spatial Modes encoding' paragraph in the 'Basics' section of the documentation) of the gate-based circuit above.\n", "\n", "The other modes are used to successfully implement two-qubit gates via heralding or post-selection. Heralding employs [4 ancillary modes](https://doi.org/10.1073/pnas.1018839108) while post-selection employs [2 ancillary modes](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.65.062324). With the option `use_postselection=True` in the method `.convert` on a `QiskitConverter` object, every CNOT but the last is implemented with a heralding scheme. Here it means that it would add $4+2$ ancillary modes. The option `use_postselection=False` only implements heralded CNOTs. Here it would mean $4+4$ ancillary modes. Note: the `use_postselection` option is `True` by default." ] }, { "cell_type": "code", "execution_count": 4, "id": "dccbd8c9", "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": "", "image/svg+xml": "\n\n\n\n\n\n\n\n\n\n\nH\n\n\n\n\n\nΦ_tl=piΦ_bl=pi\nΘ=5*pi/2\n\n\nH\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nHERALDED CNOT\n\n\n\n\n\n\n\n\n\n\n\nH\n\n\n\n\n\n\n\n\n\n\n\n\nH\n\n\n\n\n\nΦ_tl=3*pi/2Φ_bl=piΦ_tr=pi/2\nΘ=2.145993\n\n\nH\n\n\n\n\n\n\nΘ=2.145993\n\n\nH\n\n\n\n\n\n\n\n\n\nH\n\n\n\n\n\n\n\n\n\nΘ=1.028622\n\n\nH\n\n\n\n\n\nΦ_tl=3*pi/2Φ_bl=piΦ_tr=pi/2\nΘ=1.028622\n\n\nH\n\n\n\n\n\n\n\n\n\n\n\n\n\nH\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nPOSTPROCESSED CNOT\n\n\n\n\n\nΦ_tl=3*pi/2Φ_bl=piΦ_tr=pi/2\nΘ=1.910633\n\n\nH\n\n\n\n\n\n\n\n\n\nH\n\n\n\n\n\n\nΦ_tl=3*pi/2Φ_bl=piΦ_tr=pi/2\nΘ=1.910633\n\n\nH\n\n\n\n\n\n\nΘ=1.910633\n\n\nH\n\n\n\n\n\n\n\n\n\nH\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n0\n1\n[q0]\n\n2\n3\n[q1]\n\n4\n5\n[q2]\n\n[herald0]\n0\n\n[herald1]\n1\n\n[herald2]\n0\n\n[herald3]\n1\n\n[herald4]\n0\n\n[herald5]\n0\n\n0\n1\n[q0]\n\n2\n3\n[q1]\n\n4\n5\n[q2]\n\n[herald0]\n0\n\n[herald1]\n1\n\n[herald2]\n0\n\n[herald3]\n1\n\n[herald4]\n0\n\n[herald5]\n0\n" }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "qiskit_converter = QiskitConverter(catalog, backend_name=\"Naive\")\n", "quantum_processor = qiskit_converter.convert(circuit, use_postselection=True)\n", "pcvl.pdisplay(quantum_processor, recursive=True)" ] }, { "cell_type": "markdown", "id": "88ff50bd", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "With this converted circuit, we can now check that the resulting state is the same as before the conversion. By default, the input is the logical state $|000\\rangle_L$. Note that where Qiskit displays state in the order $|q_2q_1q_0\\rangle_L$, Perceval uses the reverse order $|q_0q_1q_2\\rangle_L$, but still shown as Fock states. Here, it doesn't change anything since we end with only $|000\\rangle_L$ and $|111\\rangle_L$ states." ] }, { "cell_type": "code", "execution_count": 5, "id": "8ddb1457", "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": "", "text/html": "\n\n\n\n\n\n\n\n\n\n
state probability
|1,0,1,0,1,0>1/2
|0,1,0,1,0,1>1/2
|1,0,0,1,1,0>0
|0,1,1,0,0,1>0
" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Not necessary here\n", "quantum_processor.with_input(pcvl.LogicalState([0,0,0]))\n", "\n", "sampler = pcvl.algorithm.Sampler(quantum_processor)\n", "\n", "output_distribution = sampler.probs()[\"results\"]\n", "pcvl.pdisplay(output_distribution, precision=1e-2, max_v = 4)" ] }, { "cell_type": "markdown", "id": "2f14a1c5", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "This circuit can now be converted using a general interferometer decomposition so it can be implemented on a generic photonic chip." ] }, { "cell_type": "code", "execution_count": 6, "id": "d15ff2ba", "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "u = quantum_processor.linear_circuit().compute_unitary(use_symbolic=False)" ] }, { "cell_type": "code", "execution_count": 7, "id": "1de600cb", "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": "", "image/svg+xml": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nΘ=3*pi/2\n\n\nRx\n\n\nΦ=2*pi\n\n\n\n\n\n\n\nΘ=pi\n\n\nRx\n\n\nΦ=3.586284\n\n\n\n\n\n\n\nΘ=10.655737\n\n\nRx\n\n\nΦ=pi\n\n\n\n\n\n\n\nΘ=pi\n\n\nRx\n\n\nΦ=5.789269\n\n\n\n\n\n\nΘ=10*pi/3\n\n\nRx\n\n\nΦ=pi\n\n\n\n\n\n\n\nΘ=4.372552\n\n\nRx\n\n\nΦ=0\n\n\n\n\n\n\nΘ=3*pi/2\n\n\nRx\n\n\nΦ=0.376182\n\n\n\n\n\n\n\nΘ=pi\n\n\nRx\n\n\nΦ=0.062973\n\n\n\n\n\n\nΘ=pi\n\n\nRx\n\n\nΦ=3.081369\n\n\n\n\n\n\nΘ=3*pi\n\n\nRx\n\n\nΦ=5.904254\n\n\n\n\n\n\n\nΘ=pi\n\n\nRx\n\n\nΦ=3.460472\n\n\n\n\n\n\n\nΘ=3*pi\n\n\nRx\n\n\nΦ=0.982393\n\n\n\n\n\n\nΘ=pi\n\n\nRx\n\n\nΦ=4.856823\n\n\n\n\n\n\nΘ=3*pi\n\n\nRx\n\n\nΦ=1.354757\n\n\n\n\n\n\n\nΘ=3*pi\n\n\nRx\n\n\nΦ=2.007123\n\n\n\n\n\n\n\nΘ=3*pi\n\n\nRx\n\n\nΦ=1.274398\n\n\n\n\n\n\nΘ=3*pi\n\n\nRx\n\n\nΦ=5.501469\n\n\n\n\n\n\nΘ=11.570771\n\n\nRx\n\n\nΦ=3*pi/2\n\n\n\n\n\n\n\nΘ=pi\n\n\nRx\n\n\nΦ=1.808302\n\n\n\n\n\n\n\nΘ=pi\n\n\nRx\n\n\nΦ=2.764924\n\n\n\n\n\n\nΘ=3*pi\n\n\nRx\n\n\nΦ=5.623088\n\n\n\n\n\n\nΘ=11.806155\n\n\nRx\n\n\nΦ=5.500548\n\n\n\n\n\n\n\nΘ=pi\n\n\nRx\n\n\nΦ=2.353433\n\n\n\n\n\n\n\nΘ=3.852148\n\n\nRx\n\n\nΦ=pi\n\n\n\n\n\n\n\nΘ=5*pi/2\n\n\nRx\n\n\nΦ=pi/2\n\n\n\n\n\n\n\nΘ=8.497483\n\n\nRx\n\n\nΦ=3*pi/2\n\n\n\n\n\n\n\nΘ=3*pi\n\n\nRx\n\n\nΦ=1.005773\n\n\n\n\n\n\n\nΘ=3*pi\n\n\nRx\n\n\nΦ=3.232767\n\n\n\n\n\n\nΘ=2.145993\n\n\nRx\n\n\nΦ=0\n\n\n\n\n\n\nΘ=2.431038\n\n\nRx\n\n\nΦ=3.3554\n\n\n\n\n\n\nΘ=3*pi\n\n\nRx\n\n\nΦ=1.356989\n\n\n\n\n\n\nΘ=2.381377\n\n\nRx\n\n\nΦ=pi\n\n\n\n\n\n\nΘ=8.193819\n\n\nRx\n\n\nΦ=pi/2\n\n\n\n\n\n\nΘ=10.742894\n\n\nRx\n\n\nΦ=pi/2\n\n\n\n\n\n\n\nΘ=4.913747\n\n\nRx\n\n\nΦ=pi/2\n\n\n\n\n\n\n\nΘ=pi\n\n\nRx\n\n\nΦ=4.704143\n\n\n\n\n\n\n\nΘ=1.910633\n\n\nRx\n\n\nΦ=5.019366\n\n\n\n\n\n\nΘ=pi\n\n\nRx\n\n\nΦ=2.278419\n\n\n\n\n\n\nΘ=pi\n\n\nRx\n\n\nΦ=0.876857\n\n\n\n\n\n\nΘ=pi\n\n\nRx\n\n\nΦ=3.698707\n\n\n\n\n\n\nΘ=3*pi\n\n\nRx\n\n\nΦ=1.698868\n\n\n\n\n\n\nΘ=pi\n\n\nRx\n\n\nΦ=1.773002\n\n\n\n\n\n\nΘ=3*pi\n\n\nRx\n\n\nΦ=4.082134\n\n\n\n\n\n\nΘ=pi\n\n\nRx\n\n\nΦ=5.319738\n\n\n\n\n\n\n\nΘ=pi\n\n\nRx\n\n\nΦ=1.956447\n\n\n\n\n\n\n\nΘ=1.910633\n\n\nRx\n\n\nΦ=2.517287\n\n\n\n\n\n\n\nΘ=3*pi\n\n\nRx\n\n\nΦ=5.456853\n\n\n\n\n\n\nΘ=pi\n\n\nRx\n\n\nΦ=2.055497\n\n\n\n\n\n\nΘ=3*pi\n\n\nRx\n\n\nΦ=0.966679\n\n\n\n\n\n\nΘ=3*pi\n\n\nRx\n\n\nΦ=0.853832\n\n\n\n\n\n\nΘ=pi\n\n\nRx\n\n\nΦ=0.716222\n\n\n\n\n\n\nΘ=7*pi/2\n\n\nRx\n\n\nΦ=3*pi/2\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n" }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ub = (pcvl.Circuit(2)\n", " // pcvl.BS(theta=pcvl.Parameter(\"theta\"))\n", " // (0, pcvl.PS(phi=pcvl.Parameter(\"φ_a\"))))\n", "\n", "pc_norm = pcvl.Circuit.decomposition(u, ub, shape=\"triangle\")\n", "pcvl.pdisplay(pc_norm, compact=True, render_size=0.5)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.7" } }, "nbformat": 4, "nbformat_minor": 5 }